<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace CZToolsHpf\Base;

use Closure;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use HyperfExt\Jwt\Jwt;
use Psr\Container\ContainerInterface;

use HyperfExt\Jwt\Contracts\JwtFactoryInterface;
use HyperfExt\Jwt\Contracts\ManagerInterface;

abstract class AbstractController
{
    /**
     * @Inject
     * @var ContainerInterface
     */
    protected ContainerInterface $container;

    public const MaxContent = 1000;

    /**
     * @Inject
     * @var RequestInterface
     */
    protected RequestInterface $request;

    /**
     * @Inject
     * @var ManagerInterface
     */
    protected ManagerInterface $manager;

    /**
     * @Inject
     * @var JwtFactoryInterface
     */
    protected JwtFactoryInterface $jwtFactory;

    /**
     * @Inject
     * @var Jwt
     */
    protected Jwt $jwt;

    protected static array $relationMap = [
        'between' => 'Between',
        'notbetween' => 'NotBetween',
        'in' => 'In',
        'notin' => 'NotIn',

        'eq' => '=',
        'neq' => '<>',
        'gt' => '>',
        'egt' => '>=',
        'lt' => '<',
        'elt' => '<=',

        'or' => 'or',
        'like' => '',
    ];

    /**
     * @Inject
     * @var ResponseInterface
     */
    protected ResponseInterface $response;

    protected int $pageindex;
    protected int $pagesize;

    public function _initPage()
    {
        $pageIndex = intval($this->request->post('pageindex', 1));
        $this->pageindex = max($pageIndex, 1);
        $pageSize = intval($this->request->post('pagesize', 10));
        $this->pagesize = $pageSize < 1 ? 10 : $pageSize;
    }

    public function respPage(int $code, string $msg, int $count, array $list): \Psr\Http\Message\ResponseInterface
    {
        $this->_initPage();
        $r = [
            'code' => $code,
            'msg' => $msg,
            'data' => [
                'pageindex' => $this->pageindex,
                'pagesize' => $this->pagesize,
                'count' => $count,
                'list' => $list,
                'hasmore' => count($list) < $this->pagesize ? 0 : 1,
            ]
        ];
        return $this->response->json($r);
    }

    public function respCode(int $code, string $msg, array $data = [], array $extra = []): \Psr\Http\Message\ResponseInterface
    {
        $r = [
            'code' => $code,
            'msg' => $msg,
            'data' => $data,
        ];
        if ($extra) {
            $r = array_merge($r, $extra);
        }
        return $this->response->json($r);
    }

    /**
     * @param array $matchField
     * @return  Closure
     */
    public function search(array $matchField = []): Closure
    {
        $search = $this->request->post('sword');

        return function ($query) use ($search, $matchField) {
            foreach ($search as $k => $v) {
                if (preg_match('/time/i', $k)) {
                    $column = $matchField[$k]['dbfield'] ?? $k;
                    list($start, $end) = explode("-", $v);
                    if ($start && $end) {
                        $query->where($column, '<', strtotime($end))
                            ->where($column, '>', strtotime($start));
                    } else {
                        $relation = $matchField[$k]['relation'] ?? 'gt';
                        if (in_array($relation, ['gt', 'egt', 'lt', 'elt'])) {
                            $relation = self::$relationMap[$relation];
                        } else {
                            $relation = '=';
                        }
                        $query->where($column, $relation, "DATE($start)");
                    }
                } else {
                    $search[$k] = $v;
                    $relation = '';
                    $dbField = $k;
                    if (array_key_exists($k, $matchField)) {
                        $relation = $matchField[$k]['relation'];
                        $dbField = $matchField[$k]['dbfield'] ?? $k;
                    }

                    if (in_array($relation, ['between', 'notbetween', 'in', 'notin'])) {
                        $query->${'where' . self::$relationMap[$relation]}($dbField, explode(',', $v));
                    } else if (in_array($relation, ['neq', 'gt', 'egt', 'lt', 'elt', 'eq'])) {
                        $query->where($dbField, self::$relationMap[$relation], $v);
                    } else if ($relation == 'or') {
                        $query->orWhere($dbField, $v);
                    } else if ($relation == 'like') { //支持['${matchfield}'=>['relation'=>'','dbfield'=>[ 'or'=>['title'=>'%%s', 'content'=>'%%s%', 'name'=>'%s%']]]
                        if (is_array($dbField)) {
                            foreach ($dbField as $kk => $vv) {
                                if ($kk == 'or') {
                                    foreach ($vv as $kkk => $vvv) {
                                        $symbol = preg_replace("/\%s/", $v, $vvv);
                                        $query->orWhere($kkk, 'like', $symbol);
                                    }
                                } else {
                                    foreach ($vv as $kkk => $vvv) {
                                        $symbol = preg_replace("/\%s/", $v, $vvv);
                                        $query->where($kkk, 'like', $symbol);
                                    }
                                }
                            }
                        } else {
                            $query->where($dbField, 'like', '%' . $v . '%');
                        }

                    } else {
                        $query->where($search);
                    }
                }
            }
            return $query;
        };
    }

    /**
     * 获取客户端ip
     * @return string
     */
    protected function getRealIp(): string
    {
        $headers = $this->request->getHeaders();

        if (isset($headers['x-forwarded-for'][0]) && !empty($headers['x-forwarded-for'][0])) {
            return $headers['x-forwarded-for'][0];
        } elseif (isset($headers['x-real-ip'][0]) && !empty($headers['x-real-ip'][0])) {
            return $headers['x-real-ip'][0];
        }

        $serverParams = $this->request->getServerParams();
        return $serverParams['remote_addr'] ?? '';
    }
}
